//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_SCENE_IMPORT_VRML_ZNODE_H_
#define _BUOLA_SCENE_IMPORT_VRML_ZNODE_H_

#include <buola/zz/operators.h>

#include "ztoken.h"
#include "cparser.h"
#include "cproto.h"

namespace buola { namespace scene { namespace vrml {

struct ZField : public zz::ZBase<ZField>
{
    // Define the attribute type exposed by this parser component
    template<typename tIt>
    struct tAttribute
    {
        typedef PField tType;
    };

    ZField(CParser *pParser)
        :   mParser(pParser)
    {}
    
    // This function is called during the actual parsing process
    template <typename tIt,typename tAttr,typename tCtx,typename tSk>
    bool Parse(tIt &pB,const tIt &pE,tAttr &pAttr,tCtx&,const tSk &pSk) const;

private:
    CParser *mParser;
};

inline ZField zfield(CParser *pParser)
{
    return ZField(pParser);
}

struct ZInterface : public zz::ZBase<ZInterface>
{
    // Define the attribute type exposed by this parser component
    template<typename tIt>
    struct tAttribute
    {
        typedef PInterface tType;
    };

    ZInterface(CParser *pParser)
        :   mParser(pParser)
    {}
    
    // This function is called during the actual parsing process
    template <typename tIt,typename tAttr,typename tCtx,typename tSk>
    bool Parse(tIt &pB,const tIt &pE,tAttr &pAttr,tCtx&,const tSk &pSk) const;

private:
    CParser *mParser;
};

inline ZInterface zinterface(CParser *pParser)
{
    return ZInterface(pParser);
}

struct ZNode : public zz::ZBase<ZNode>
{
    // Define the attribute type exposed by this parser component
    template<typename tIt>
    struct tAttribute
    {
        typedef PNode tType;
    };

    ZNode(CParser *pParser)
        :   mParser(pParser)
    {}
    
    ZNode(const ZNode &pNode)
        :   mParser(pNode.mParser)
    {}
    
    // This function is called during the actual parsing process
    template <typename tIt,typename tAttr,typename tCtx,typename tSk>
    bool Parse(tIt &pB,const tIt &pE,tAttr &pAttr,tCtx&,const tSk &pSk) const;

private:
    CParser *mParser;
};

inline ZNode znode(CParser *pParser)
{
    return ZNode(pParser);
}

struct ZProto : public zz::ZBase<ZProto>
{
    // Define the attribute type exposed by this parser component
    template<typename tIt>
    struct tAttribute
    {
        typedef PProto tType;
    };

    ZProto(CParser *pParser)
        :   mParser(pParser)
    {}
    
    ZProto(const ZProto &pProto)
        :   mParser(pProto.mParser)
    {}
    
    // This function is called during the actual parsing process
    template <typename tIt,typename tAttr,typename tCtx,typename tSk>
    bool Parse(tIt &pB,const tIt &pE,tAttr &pAttr,tCtx&,const tSk &pSk) const;

private:
    CParser *mParser;
};

inline ZProto zproto(CParser *pParser)
{
    return ZProto(pParser);
}

template <typename tIt,typename tAttr,typename tCtx,typename tSk>
bool ZNode::Parse(tIt &pB,const tIt &pE,tAttr &pAttr,tCtx&,const tSk &pSk) const
{
    PNode lNode=new CNode;
    
    auto rNodeElement=zfield(mParser)--[lNode->mFields] |
                      mParser->rRouteStatement | 
                      zproto(mParser)--[lNode->mProtos] |
                      mParser->rExternProto |
                      zinterface(mParser) |
                      (ztoken(TOKEN_KW_EVENTIN)>>ztoken(TOKEN_IDENTIFIER)>>ztoken(TOKEN_IDENTIFIER)>>ztoken(TOKEN_KW_IS)>>ztoken(TOKEN_IDENTIFIER)) |
                      (ztoken(TOKEN_KW_EVENTOUT)>>ztoken(TOKEN_IDENTIFIER)>>ztoken(TOKEN_IDENTIFIER)>>ztoken(TOKEN_KW_IS)>>ztoken(TOKEN_IDENTIFIER)) |
                      (ztoken(TOKEN_KW_FIELD)>>ztoken(TOKEN_IDENTIFIER)>>ztoken(TOKEN_IDENTIFIER)>>ztoken(TOKEN_KW_IS)>>ztoken(TOKEN_IDENTIFIER));

    auto rParser=(ztoken(TOKEN_KW_USE)>>ztoken(TOKEN_IDENTIFIER)--(lNode->mUse))|
                 (-(ztoken(TOKEN_KW_DEF)>>ztoken(TOKEN_IDENTIFIER)--(lNode->mDef)) >> ztoken(TOKEN_IDENTIFIER)--(lNode->mType) >>
                                ztoken(TOKEN_LEFT_BRACE) >> *rNodeElement >> ztoken(TOKEN_RIGHT_BRACE));
    
    UUnused lAttr;
    UUnused lCtx;
    bool lOk=rParser.Parse(pB,pE,lAttr,lCtx,pSk);
    
    if(lOk)
    {
//        msg_info() << lNode->mType.Text() << " " << lNode->mDef.Text() << " " << lNode->mUse.Text() << " " <<
//                      lNode->mFields.size() << "\n";
        pAttr=lNode;
    }
    
    return lOk;
}

template <typename tIt,typename tAttr,typename tCtx,typename tSk>
bool ZField::Parse(tIt &pB,const tIt &pE,tAttr &pAttr,tCtx&,const tSk &pSk) const
{
    PField lField=new CField;
    CToken lToken;
    PNode lNode;
    
    auto rSFString=zattrtoken(TOKEN_STRING)--(lToken);
    auto rSFNumeric=(+zattrtokentype(TOKENTYPE_NUMBER))--(lField->mTokens);
    auto rSFNode=znode(mParser)--(lNode)|ztoken(TOKEN_KW_NULL);
    auto rSFBool=(zattrtoken(TOKEN_KW_TRUE)|zattrtoken(TOKEN_KW_FALSE))--(lToken);
    auto rMFString=ztoken(TOKEN_LEFT_SQUARE)>>(+zattrtoken(TOKEN_STRING))--(lField->mTokens)>>ztoken(TOKEN_RIGHT_SQUARE);
    auto rMFNumeric=ztoken(TOKEN_LEFT_SQUARE)>>(+zattrtokentype(TOKENTYPE_NUMBER))--(lField->mTokens)>>ztoken(TOKEN_RIGHT_SQUARE);
    auto rMFNode=ztoken(TOKEN_LEFT_SQUARE)>>(+znode(mParser))--(lField->mNodes)>>ztoken(TOKEN_RIGHT_SQUARE);
    auto rMFEmpty=ztoken(TOKEN_LEFT_SQUARE)>>ztoken(TOKEN_RIGHT_SQUARE);
    
    auto rParser=(ztoken(TOKEN_IDENTIFIER)--(lField->mIdentifier) >> (rSFString|rSFNumeric|rSFNode|rSFBool|rMFString|rMFNumeric|rMFNode|rMFEmpty)) |
                 (ztoken(TOKEN_IDENTIFIER)--(lField->mIdentifier) >>ztoken(TOKEN_KW_IS)>>ztoken(TOKEN_IDENTIFIER)--(lField->mIs));
    UUnused lAttr;
    UUnused lCtx;
    bool lOk=rParser.Parse(pB,pE,lAttr,lCtx,pSk);
    
    if(lOk)
    {
        if(lNode)
            lField->mNodes.push_back(lNode);
        if(lToken.mToken!=TOKEN_INVALID)
            lField->mTokens.push_back(lToken);
            
        pAttr=lField;
//        msg_info() << lField->mIdentifier.Text() << " " << lField->mTokens.size() << " " << lField->mNodes.size() << "\n";
    }
    return lOk;
}

template <typename tIt,typename tAttr,typename tCtx,typename tSk>
bool ZInterface::Parse(tIt &pB,const tIt &pE,tAttr &pAttr,tCtx&,const tSk &pSk) const
{
    PInterface lInterface=new CInterface;
    auto rParser=(ztokentype(TOKENTYPE_KW_EVENT)>>ztokentype(TOKENTYPE_FIELDTYPE)>>ztoken(TOKEN_IDENTIFIER)) |
                     (ztokentype(TOKENTYPE_KW_FIELD)>>ztokentype(TOKENTYPE_FIELDTYPE)>>zfield(mParser)--(lInterface->mField));
    
    UUnused lAttr;
    UUnused lCtx;
    bool lOk=rParser.Parse(pB,pE,lAttr,lCtx,pSk);
    
    if(lOk)
    {
        pAttr=lInterface;
//        msg_info() << lField->mIdentifier.Text() << " " << (int)lField->mToken.mToken << " " << 
//                      lField->mTokens.size() << " " << (bool)lField->mNode << " " << lField->mNodes.size() << "\n";
    }
    return lOk;
}

template <typename tIt,typename tAttr,typename tCtx,typename tSk>
bool ZProto::Parse(tIt &pB,const tIt &pE,tAttr &pAttr,tCtx&,const tSk &pSk) const
{
    PProto lProto=new CProto;
    
    const auto &rParser=ztoken(TOKEN_KW_PROTO) >> ztoken(TOKEN_IDENTIFIER)--(lProto->mName) >>
           ztoken(TOKEN_LEFT_SQUARE) >> *zinterface(mParser)--[lProto->mInterfaces] >> ztoken(TOKEN_RIGHT_SQUARE) >>
           ztoken(TOKEN_LEFT_BRACE) >> *(znode(mParser)--[lProto->mNodes]|zproto(mParser)|mParser->rExternProto|mParser->rRouteStatement) >> ztoken(TOKEN_RIGHT_BRACE);

    UUnused lAttr;
    UUnused lCtx;
    bool lOk=rParser.Parse(pB,pE,lAttr,lCtx,pSk);
    
    if(lOk)
    {
        pAttr=lProto;
        //msg_info() << lProto->mName.Text() << " " << (int)lProto->mNodes.size() << "\n";
    }
    return lOk;
}

/*namespace vrml*/ } /*namespace scene*/ } /*namespace buola*/ }

#endif
